package net.sourceforge.gomoku

import java.io.File
import collection.mutable.{ArrayBuffer, ListBuffer}
import xml.{Node, XML}

object PatternSet{
  val patternsFile = "/opt/tmp/gomoku-patterns6.xml"
  //val patternsFile = "/opt/project/scala-agent3/modules/scalaagent/src/main/resources/gomoku-patterns.xml"

  def loadPatternSet = PatternSet(loadPatternsFromFile)

  def loadPatternsFromFile:Set[Pattern] = {
    val f = new File(patternsFile)
    if( !f.exists ){
      val p1 = Pattern(Set(Cell(1,0),Cell(2,0),Cell(3,0),Cell(4,0)),
        Set(Cell(5,0)), Cell(5,0)).zeroShift
      val p2 = Pattern(Set(Cell(1,0),Cell(2,0),Cell(3,0),Cell(5,0)),
        Set(Cell(4,0)), Cell(4,0)).zeroShift
      val p3 = Pattern(Set(Cell(1,0),Cell(2,0),Cell(4,0),Cell(5,0)),
        Set(Cell(3,0)), Cell(3,0)).zeroShift

      val p1d = Pattern(Set(Cell(1,1),Cell(2,2),Cell(3,3),Cell(4,4)),
        Set(Cell(5,5)), Cell(5,5)).zeroShift
      val p2d = Pattern(Set(Cell(1,1),Cell(2,2),Cell(3,3),Cell(5,5)),
        Set(Cell(4,4)), Cell(4,4)).zeroShift
      val p3d = Pattern(Set(Cell(1,1),Cell(2,2),Cell(4,4),Cell(5,5)),
        Set(Cell(3,3)), Cell(3,3)).zeroShift

      p1.idTrack = IdTrack(1)
      p2.idTrack = IdTrack(2)
      p3.idTrack = IdTrack(3)

      p1d.idTrack = IdTrack(4)
      p2d.idTrack = IdTrack(5)
      p3d.idTrack = IdTrack(6)

      Set(p1,p2,p3, p1d,p2d,p3d)

//      Set[Pattern]()
    }else{
      (for( n <- XML.loadFile( f ) \\ "pattern" ) yield patFromXML(n) ).toSet
    }
  }

  def patFromXML(n:Node)={
    val p = Pattern.patternFromPrintView(n.text)
    p.idTrack = IdTrack((n \ "@id").text.toInt)
    if( !p.continuous ){
      printf("loaded pattern NOT CONTINUOUS! %s %n", p.idTrack)
    }
    for( pi <- p.allSymetries; if !pi.continuous ){
      printf("loaded pattern symmetry NOT CONTINUOUS! %s %n%s%n----%n%s%n-----%n",
        p.idTrack, p.printView, pi.printView )
    }
    p
  }

}

case class PatternSet(ps: Set[Pattern]){

  def +(p:Pattern)={
    assert(p.idTrack == null)

    if( ps.forall( pi => !p.contains(pi) ) ){
      val newId = ps.map(p => p.idTrack.id).max + 1
      p.idTrack = IdTrack(newId)
      printf("creating new pattern ID %s %n", p.idTrack)
      PatternSet(ps.filterNot( pi => pi contains p  ) + p)
    }else{
      this
    }


//    for( pi <- ps ){
//      if( (pi contains p) || (p contains pi) ){
//        printf("contains condition%n%s%n-------%n%s%n------%n", pi.printView, p.printView)
//        System.nanoTime
//      }
//    }

  }

  def exportPatterns()={
    <patterns>
      { for( p <- ps.toArray.sortBy( _.idTrack.id ) ) yield
        <pattern id={p.idTrack.id.toString}>
{ p.printView }
        </pattern>
      }
    </patterns>
  }


  def savePattersToFile(){
    XML.save( PatternSet.patternsFile, exportPatterns, "utf-8", true, null )
  }

  def size = ps.size

  def findEnemyPatterns(b:Board, oneOf: Pattern, myPiece:Int):Seq[MaterializedPattern] = {
    assert( oneOf.minXY == Cell(0,0) )

    val ret = new ListBuffer[MaterializedPattern]
    val max = oneOf.maxXY
    for( x <- 0 to (b.getCols - 1 - max.x); y <- 0 to (b.getRows - 1 - max.y) ){
      var ok=true
      for( c <- oneOf.marks ){
        val pi = b.getPiece(y+c.y, x+c.x)
        if( pi==0 || pi==myPiece ){
          ok=false
        }
      }
      for( c <- oneOf.empty ){
        val pi = b.getPiece(y+c.y, x+c.x)
        if( pi!=0 ){
          ok=false
        }
      }
      if( ok ){
        ret += MaterializedPattern( oneOf, Cell(x,y) )
      }
    }
    ret
  }

  def findMyPossiblePatterns(b:Board, oneOf: Pattern, myPiece:Int):Seq[PossiblePattern] = {
    assert( oneOf.minXY == Cell(0,0) )
    val ret = new ArrayBuffer[PossiblePattern]
    val max = oneOf.maxXY
    for( x <- 0 to (b.getCols - 1 - max.x); y <- 0 to (b.getRows - 1 - max.y) ){
      def emptyTest = (c:Cell) => b.getPiece(y+c.y, x+c.x)==0
      if( oneOf.empty.forall( emptyTest  ) ){
        if( oneOf.marks.forall{ c => val p = b.getPiece(y+c.y, x+c.x); p==0 || p==myPiece } ){
          val missing = oneOf.marks.filter( emptyTest )
          ret += new PossiblePattern(oneOf, missing, Cell(x,y))
        }
      }
    }
    ret
  }

  def findEnemyPatterns(b:Board, myPiece:Int):Seq[MaterializedPattern] = {
    val ret = new ListBuffer[MaterializedPattern]
    for( pat <- ps; sym <- pat.allSymetries ){
      ret ++= findEnemyPatterns (b, sym, myPiece)
    }
    ret
  }

  def findMyPossiblePatterns(b:Board, myPiece:Int):Seq[PossiblePattern] = {
    val ret = new ListBuffer[PossiblePattern]
    for( pat <- ps; sym <- pat.allSymetries ){
      ret ++= findMyPossiblePatterns (b, sym, myPiece)
    }
    ret
  }

}